package com.congee02.modelshellmvn.aop;

import com.congee02.modelshellmvn.anno.NeedSave;
import com.congee02.modelshellmvn.anno.RecordAdapter;
import com.congee02.modelshellmvn.utils.AnnotationUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
@SuppressWarnings({"rawtypes", "unchecked"})
public class RecordAspect implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Pointcut("@annotation(com.congee02.modelshellmvn.anno.NeedSave)")
    public void needRecordAnnotatedMethod() {}

    @AfterReturning(pointcut = "needRecordAnnotatedMethod()", returning = "result")
    public Object saveRecord(final JoinPoint joinPoint, Object result) {
        NeedSave needSave = AnnotationUtils.extractAnnotationFromJoinPoint(
                joinPoint, NeedSave.class
        );
        JpaRepository repo = applicationContext.getBean(
                needSave.repo()
        );
        Object updated = adaptAndSave(
                result, repo, applicationContext.getBean(
                        needSave.adapter()
                )
        );
        return needSave.returnUpdated() ? updated : result;
    }

    public Object adaptAndSave(
            Object result, JpaRepository repo, RecordAdapter adapter
    ) {
        if (result instanceof Iterable) {
            return repo.saveAll(
                    adapter.adaptMulti(
                            (Iterable) result
                    )
            );
        }
        return repo.save(
                adapter.adapt(result)
        );
    }


}
